﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Clandestine.Entities;

namespace Clandestine
{
    public static class Collision
    {
        public static float ActiveLayer
        {
            get { return (WorldMap.Player != null) ? WorldMap.Player.Layer : 0; }
        }

        public static bool TryTriggerUseEvent(Rectangle playerRectangle)
        {
            if (WorldMap.Level == null)
            {
                //Log.w("Collision.TryTriggerUseEvent() called, but there is no world!");
                Log.v("TryTriggerUseEvent: World not ready.");
                return false;
            }

            Entity bestUseMatch = null;
            double bestUseMatchWeight = -1;

            lock (WorldMap.Level.Entities.LoadedEntities)
            {
                foreach (Entity e in WorldMap.Level.Entities.LoadedEntities.Values)
                {
                    if (e.Layer == ActiveLayer)
                    {
                        if (e.CanUse)
                         {
                            Rectangle r = intersect(e.UseRectangle, playerRectangle);
                            double weight = Math.Sqrt(r.Width * r.Width + r.Height * r.Height);
                            if (weight > 0.0 && weight > bestUseMatchWeight)
                                bestUseMatch = e;
                        }
                    }
                }
            }

            if (bestUseMatch != null)
            {
                bestUseMatch.OnUse(playerRectangle.X, playerRectangle.Y);
                return true;
            }
            else
                return false;
        }

        public static bool TryTriggerCollideEvent(Rectangle playerRectangle)
        {
            if (WorldMap.Level == null)
            {
                //Log.w("Collision.TryTriggerCollideEvent() called, but world is not present!");
                Log.v("TryTriggerCollideEvent: World not ready.");
                return false;
            }

            bool collided = false;

            Entity[] buffer;
            lock (WorldMap.Level.Entities.LoadedEntities)
                buffer =  WorldMap.Level.Entities.LoadedEntities.Values.ToArray();

            foreach (Entity e in buffer)
            {
                if (e.Layer == ActiveLayer)
                {
                    if (intersects(e.CollisionRectangle, playerRectangle))
                    {
                        e.OnCollide(playerRectangle.X, playerRectangle.Y);
                        collided = true;
                    }
                }
            }

            return collided;
        }

        public static bool CheckCollision(Rectangle ourRectangle, float layer)
        {
            return CheckCollision(ourRectangle, false, layer, null);
        }
        public static bool CheckCollision(Rectangle ourRectangle, bool IncludePlayer, float layer, Entity excludeEntity)
        {
            bool goBackToOldPos = false;
            lock (WorldMap.Level.Entities.LoadedEntities)
            {
                // entities
                foreach (Entity e in WorldMap.Level.Entities.LoadedEntities.Values)
                {
                    if (e != excludeEntity)
                        if (e.Layer == layer)
                        {
                            if (intersects(e.CollisionRectangle, ourRectangle))
                            {
                                if (e.Solid)
                                    goBackToOldPos = true;
                            }
                        }
                }

                // player
                if (IncludePlayer)
                    if (intersects(WorldMap.Player.GetCollisionRectangle(), ourRectangle))
                       goBackToOldPos = true;
            }

            return goBackToOldPos;
        }

        public static PointF TryMove(PointF initialPosition, PointF newPosition, Size size)
        {
            if (WorldMap.Level == null)
            {
                //Log.w("Collision.TryMove() is being called, but WorldMap.Level is null!");
                //Log.w("Approving move anyway.");
                Log.v("TryMove: World not ready.");
                return newPosition;
            }  

            Point pos = Point.Round(newPosition);
            Rectangle ourRectangle = WorldMap.Player.GetCollisionRectangle(pos);
            bool goBackToOldPos = CheckCollision(ourRectangle, ActiveLayer);

            if (goBackToOldPos)
                return initialPosition;
            else
            {
                // Going to put the screen-movement code here for now as it will be checking if we're
                // 'colliding' with the border, etc.
                Camera.UpdateScrolling(Point.Round(newPosition));

                return newPosition;
            }
        }

        private static bool intersects(Rectangle tthis, Rectangle value)
        {
            return (tthis.Bottom > value.Top && tthis.Top < value.Bottom && tthis.Left < value.Right
                && tthis.Right > value.Left);
        }

        private static Rectangle intersect(Rectangle value1, Rectangle value2)
        {
            int lx = value1.Left;
            int rx = value1.Right;
            int uy = value1.Top;
            int dy = value1.Bottom;

            if (value2.Left > value1.Left)
                lx = value2.Left;
            if (value2.Top > value1.Top)
                uy = value2.Top;
            if (value2.Bottom < value1.Bottom)
                dy = value2.Bottom;
            if (value2.Right < value1.Right)
                rx = value2.Right;

            if (lx >= rx || uy >= dy)
                return Rectangle.Empty;
            else
                return new Rectangle(lx, uy, rx - lx, dy - uy);
        }
    }
}
